package cn.iocoder.yudao.module.infra.service.category;

import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.infra.constant.RedisKeyConstants;
import cn.iocoder.yudao.module.infra.controller.admin.category.vo.CategoryListVO;
import cn.iocoder.yudao.module.infra.controller.admin.category.vo.CategorySaveReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.category.vo.CategorySimpleRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.category.vo.CategoryTableRespVO;
import cn.iocoder.yudao.module.infra.convert.TreeConvert;
import cn.iocoder.yudao.module.infra.convert.category.CategoryConvert;
import cn.iocoder.yudao.module.infra.dal.dataobject.category.CategoryDO;
import cn.iocoder.yudao.module.infra.dal.mysql.category.CategoryMapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.CATEGORY_NOT_EXISTS;

/**
 * TODO
 *
 * @author sun
 * @date 16:18 2023/12/4
 **/
@Service
public class CategoryServiceImpl implements CategoryService {
    @Resource
    private CategoryMapper categoryMapper;

    @Override
    @CacheEvict(value = RedisKeyConstants.CLASSIFY_KEY, allEntries = true) // 指定要清除的缓存名称为 RedisKeyConstants.CLASSIFY_KEY，allEntries = true 表示清空这个缓存空间中的所有条目
    public Long createCategory(CategorySaveReqVO reqVO) {
        CategoryDO categoryDO = CategoryConvert.INSTANCE.convert(reqVO);
        categoryDO.setStatus(0);

        categoryDO.setCreateTime(DateUtils.now());
        categoryDO.setUpdateTime(DateUtils.now());

        categoryMapper.insert(categoryDO);
        return categoryDO.getId();
    }

    @CacheEvict(value = RedisKeyConstants.CLASSIFY_KEY, allEntries = true) // 指定要清除的缓存名称为 RedisKeyConstants.CLASSIFY_KEY，allEntries = true 表示清空这个缓存空间中的所有条目
    @Override
    public void updateCategory(CategorySaveReqVO updateReqVO) {
        // 校验存在
        validateCategoryExists(updateReqVO.getId());
        // 更新
        CategoryDO updateObj = CategoryConvert.INSTANCE.convert(updateReqVO);
        categoryMapper.updateById(updateObj);
    }
    private void validateCategoryExists(Long id) {
        if (categoryMapper.selectById(id) == null) {
            throw exception(CATEGORY_NOT_EXISTS);
        }
    }

    @Override
    @CacheEvict(value = RedisKeyConstants.CLASSIFY_KEY, allEntries = true) // 指定要清除的缓存名称为 RedisKeyConstants.CLASSIFY_KEY，allEntries = true 表示清空这个缓存空间中的所有条目
    public Boolean deleteCategory(Long id) {
        // 校验存在
        validateCategoryExists(id);
        // 校验是否有子集
        if (categoryMapper.selectList(new LambdaQueryWrapperX<CategoryDO>().eq(CategoryDO::getParentId, id)).size() == 0) {
            // 删除
            categoryMapper.deleteById(id);
            return true;
        } else {
            return false;
        }

    }


    @Override
    public List<CategoryDO> getCategoryList(CategoryListVO reqVO) {
        return categoryMapper.selectList(reqVO);
    }

    @Override
    public List<CategoryDO> getSimpleCategoryList(CategoryListVO pageReqVO) {
        List<CategoryDO> categoryDOS = categoryMapper.selectSimpleList(pageReqVO);
        List<Long> list = new ArrayList<>();
        list.add(pageReqVO.getParentId());
        getParentId(categoryDOS, list, pageReqVO.getParentId());
        return categoryDOS.stream().filter(categoryDO -> list.contains(categoryDO.getId())).collect(Collectors.toList());
    }

    @Override
    @Cacheable(value = RedisKeyConstants.CLASSIFY_KEY, unless = "#result==null")
    public List<CategoryDO> getAllSimpleCategoryList(CategoryListVO vo) {
        return categoryMapper.selectSimpleList(vo);
    }

    @Cacheable(value = RedisKeyConstants.CLASSIFY_KEY, key = "#code", unless = "#result==null")
    @Override
    public List<CategoryDO> getCategoryByCode(String code) {
        return categoryMapper.selectCategoryByCode(code);
    }

    @Override
    public CategoryTableRespVO getCategory(Long id) {
        CategoryDO categoryDO = categoryMapper.selectById(id);
        return CategoryConvert.INSTANCE.convert(categoryDO);
    }

    @Override
    public List<CategorySimpleRespVO> tree(CategoryListVO categoryListVO) {
        List<CategoryDO> list = this.getAllSimpleCategoryList(categoryListVO);
        // 排序后，返回给前端
        list.sort(Comparator.comparing(CategoryDO::getSort));
        List<CategorySimpleRespVO> categorySimpleRespVOList = CategoryConvert.INSTANCE.convertList02(list);
        TreeConvert<CategorySimpleRespVO> treeConvert = new TreeConvert();
        return treeConvert.convertTree(categorySimpleRespVOList);
    }

    @Override
    public List<CategorySimpleRespVO> tree(CategoryListVO categoryListVO, Map<String, Long> countMap) {
        List<CategoryDO> list = this.getAllSimpleCategoryList(categoryListVO);
        // 排序后，返回给前端
        list.sort(Comparator.comparing(CategoryDO::getSort));
        List<CategorySimpleRespVO> categorySimpleRespVOList = CategoryConvert.INSTANCE.convertList02(list);
        TreeConvert<CategorySimpleRespVO> treeConvert = new TreeConvert();
        return treeConvert.convertTree(categorySimpleRespVOList,countMap);
    }

    private void getParentId(List<CategoryDO> categoryDOS, List<Long> list, Long parentId) {
        List<Long> collect = categoryDOS.stream().filter(categoryDO -> Objects.equals(parentId, categoryDO.getParentId())).map(CategoryDO::getId).collect(Collectors.toList());
        if (!collect.isEmpty()) {
            list.addAll(collect);
            for (Long aLong : collect) {
                getParentId(categoryDOS, list, aLong);
            }
        }

    }

}
